import 'package:family_expense/features/bank_card/models/bank_card.dart';
import 'package:family_expense/features/income_expense/constants/income_expense_type.dart';
import 'package:family_expense/features/income_expense/constants/payment_type.dart';
import 'package:family_expense/features/income_expense/models/income_expense_detail.dart';
import 'package:family_expense/features/income_expense/services/income_expense_detail_service.dart';
import 'package:family_expense/features/income_expense/widgets/edit_income_expense_detail.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_shared.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_view.dart';
import 'package:flutter/material.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

class IncomeExpenseSearchArguments {
  IncomeExpenseSearchArguments({
    this.startDate,
    this.endDate,
    this.keyword,
    this.type,
    this.detailType,
    this.paymentType,
    this.bankCard,
    this.keywordsSearchCondition =
        keywordsSearchOrCondition, // If search against multiple keywords then which search condition would be applied between them. OR or AND.
  });

  static const String keywordsSearchOrCondition = 'OR';
  static const String keywordsSearchAndCondition = 'AND';

  DateTime? startDate;
  DateTime? endDate;
  String? type;
  String? detailType;
  String? paymentType;
  BankCard? bankCard;
  String? keyword;
  String? keywordsSearchCondition;
}

class IncomeExpenseSearchResult extends StatefulWidget {
  const IncomeExpenseSearchResult({super.key, this.searchArguments});

  final IncomeExpenseSearchArguments? searchArguments;

  @override
  State<IncomeExpenseSearchResult> createState() =>
      _IncomeExpenseSearchResultState();
}

class _IncomeExpenseSearchResultState extends State<IncomeExpenseSearchResult> {
  final int _pageSize = GeneralConfig.listViewPageSize;

  // Retrieves income/expense list.
  final IncomeExpenseDetailService _incomeExpenseDetailService =
      IncomeExpenseDetailService();

  // Used to notify last view that item has been updated.
  bool _dataUpdated = false;

  double _totalAmount = 0;

  // Used to reset the list once the income/expense detail updated.
  late PagingListViewLoadController _loadController;

  @override
  void initState() {
    super.initState();

    _queryTotalAmountByAccountGroup();
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvokedWithResult: _onPopInvokedWithResult,
      child: Scaffold(
        // With Flutter 1.7 or higher version the [RefreshIndicator] cannot be used with [CustomScrollView].
        // Consider to use [NestedScrollView] instead.
        body: NestedScrollView(
          headerSliverBuilder: (context, innerBoxScrolled) => [_buildAppBar()],
          body: _buildPagingList(),
        ),
      ),
    );
  }

  /// Builds the app bar.
  Widget _buildAppBar() {
    return SliverAppBar(
      expandedHeight: 140.0,
      pinned: true,
      floating: true,
      snap: true,
      flexibleSpace: FlexibleSpaceBar(
        background: Container(
          margin: const EdgeInsets.only(left: 70.0, top: 40.0),
          child: Opacity(
            opacity: 0.6,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  _getSearchDateInfo(),
                  style: TextStyle(
                    color: calculateContrastingColor(
                      Theme.of(context).appBarTheme.backgroundColor!,
                    ),
                  ),
                ),
                const SizedBox(height: 6.0),
                Text(
                  _getSearchTypeAndDetailTypeInfo(),
                  style: TextStyle(
                    color: calculateContrastingColor(
                      Theme.of(context).appBarTheme.backgroundColor!,
                    ),
                  ),
                ),
                const SizedBox(height: 6.0),
                Text(
                  widget.searchArguments!.keyword ?? '[详情/备注]',
                  style: TextStyle(
                    color: calculateContrastingColor(
                      Theme.of(context).appBarTheme.backgroundColor!,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
        title: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Text color auto changes if primary color changes.
            // That's why [AmountSymbol] is not used here.
            Padding(
              padding: const EdgeInsets.only(right: 1.0),
              child: Text(
                _totalAmount >= 0 ? '+' : '-',
                style: TextStyle(
                  color: calculateContrastingColor(
                    Theme.of(context).appBarTheme.backgroundColor!,
                  ),
                  fontSize: 11.0,
                ),
              ),
            ),
            Text(
              formatNumber(_totalAmount.abs()),
              style: TextStyle(
                color: calculateContrastingColor(
                  Theme.of(context).appBarTheme.backgroundColor!,
                ),
              ),
            ),
          ],
        ),
      ),
      actions: <Widget>[
        FutureBuilder<User?>(
          future: AuthStateService.instance.currentUser,
          builder: (context, userSnapshot) {
            if (userSnapshot.data?.isViewerOnly == false) {
              return IconButton(
                icon: const Icon(Icons.add),
                onPressed: () => NavigatorHelper.push(
                  context,
                  const EditIncomeExpenseDetail(),
                ),
              );
            }

            return Container();
          },
        ),
      ],
    );
  }

  /// Builds the paging list.
  Widget _buildPagingList() {
    return PagingListView(
      pageSize: _pageSize,
      getLoadController: (loadController) => _loadController = loadController,
      retrieveData: (pageIndex) =>
          _incomeExpenseDetailService.queryListByAccountGroup(
            _pageSize,
            pageIndex!,
            searchArguments: widget.searchArguments,
          ),
      refreshed: _queryTotalAmountByAccountGroup,
      itemBuilder: (context, entry, index) {
        final item = entry as IncomeExpenseDetail;

        return IncomeExpenseDetailListTile(
          item,
          () async {
            final dataUpdated = await NavigatorHelper.push<bool>(
              context,
              IncomeExpenseDetailView(item.id!),
            );

            // If the income/expense details is updated we need to refresh the list and recalculate total ammount.
            if (dataUpdated == true) {
              final res = await _incomeExpenseDetailService
                  .queryTotalAmountByAccountGroup(
                    searchArguments: widget.searchArguments!,
                  );

              if (mounted) {
                setState(() => _totalAmount = res);
              }

              _loadController.reset();

              // We only need to set [_dataUpdated] as true when [dataUpdated] is true.
              //
              // - When user chaged one item then [dataUpdated] is true and [_dataUpdated] is true.
              // - When user goes to edit view and gets back without any change, then [dataUpdated] is false.
              // But we still need to notify last page that some items have been changed.
              //
              // That's why we cannnot set [_dataUpdated] to false when [dataUpdated] is false.
              _dataUpdated = true;
            }
          },
          displayIncomeExpenseDate: true,
          keywords: widget.searchArguments!.keyword?.split(' '),
        );
      },
    );
  }

  Future<void> _queryTotalAmountByAccountGroup() async {
    final res = await _incomeExpenseDetailService
        .queryTotalAmountByAccountGroup(
          searchArguments: widget.searchArguments!,
        );

    if (mounted) {
      setState(() => _totalAmount = res);
    }
  }

  /// Gets the readable info based on different search date arguments.
  String _getSearchDateInfo() {
    String info;

    if (widget.searchArguments!.startDate == null) {
      info = '[开始日期] -- ';
    } else {
      info =
          '${widget.searchArguments!.startDate.formatDate(DatePatterns.longDate)} -- ';
    }

    if (widget.searchArguments!.endDate == null) {
      info += '[结束日期]';
    } else {
      info += widget.searchArguments!.endDate.formatDate(DatePatterns.longDate);
    }

    return info;
  }

  /// Gets the readable info based on different search type and detail type arguments.
  String _getSearchTypeAndDetailTypeInfo() {
    String info;

    if (widget.searchArguments!.type.isNullOrEmpty) {
      info = '[收支] -- ';
    } else {
      info =
          '${IncomeExpenseType.getCategories()[widget.searchArguments!.type!]} -- ';
    }

    if (widget.searchArguments!.paymentType.isNullOrEmpty) {
      info += '[收支方式] -- ';
    } else {
      info +=
          '${PaymentType.getCategories()[widget.searchArguments!.paymentType!] ?? ''} -- ';
    }

    if (widget.searchArguments!.detailType.isNullOrEmpty) {
      info += '[收支类型]';
    } else {
      info += IncomeExpenseDetailShared.getIncomeOrExpenseTypeTitle(
        IncomeExpenseDetail(
          type: widget.searchArguments!.type,
          detailType: widget.searchArguments!.detailType,
        ),
      );
    }

    return info;
  }

  void _onPopInvokedWithResult(bool didPop, dynamic result) {
    if (didPop) {
      return;
    }

    NavigatorHelper.pop(context, _dataUpdated);
  }
}
